<template>
  <view class="my-equi">
    <!-- 我的设备列表开始 -->
    <view class="title u-font-40 u-m-b-24 u-p-l-24"> 我的设备 </view>
    <view v-if="equi_list.length > 0" class="scroll-view u-p-24 u-m-b-24" scroll-y="true">
      <!-- 每一项开始 -->
      <view class="u-m-b-20" v-for="(item, index) in equi_list" :key="index">
        <view class="">
          <u-swipe-action
            :show="item.is_show"
            @click.stop="delEqui(index)"
            @open="showDel"
            :options="options"
            :index="index"
            btn-width="64"
          >
            <view
              class="eq-item bg-white u-p-l-24 u-p-t-32 u-p-r-24 u-p-b-32"
              @tap="connectEqui(item.info)"
            >
              <!-- 上面部分开始 -->
              <view class="item-top u-flex u-m-b-8">
                <view class="top-title"> 设备名称 </view>
                <view class="top-text black-color u-line-1 u-m-r-24 u-line-1">
                  {{ item.title }}
                </view>
                <view class="top-img u-flex u-col-center" @tap.stop="changeName(index)">
                  <image src="../../static/image/my/ic_xiugai@2x.png" mode=""></image>
                </view>
              </view>
              <!-- 上面部分结束 -->

              <!-- 下面部分开始 -->
              <view class="item-bottom u-flex">
                <view class="bottom-title"> 设备ID </view>
                <view class="bottom-text black-color u-line-1">
                  {{ item.eq_id }}
                </view>
              </view>
              <!-- 下面部分结束 -->
            </view>
          </u-swipe-action>
        </view>
      </view>
      <!-- 每一项结束 -->
    </view>
    <!-- 我的设备列表结束 -->
    <!-- 列表开始 -->
    <view class="title u-p-l-24 u-font-40"> 附近设备 </view>
    <view v-if="near_list.length > 0" class="scroll-view u-p-24" scroll-y="true">
      <!-- 每一项开始 -->
      <view
        class="u-m-b-20"
        v-for="(item, index) in near_list"
        :key="index"
        @click="connectEqui(item)"
      >
        <view class="eq-item bg-white u-p-l-24 u-p-t-32 u-p-r-24 u-p-b-32">
          <!-- 上面部分开始 -->
          <view class="item-top u-flex u-m-b-8">
            <view class="top-title"> 设备名称 </view>
            <view class="top-text black-color u-line-1 u-m-r-24 u-line-1">
              {{ item.name }}
            </view>
          </view>
          <!-- 上面部分结束 -->

          <!-- 下面部分开始 -->
          <view class="item-bottom u-flex">
            <view class="bottom-title"> 设备ID </view>
            <view class="bottom-text black-color u-line-1">
              {{ item.deviceId }}
            </view>
          </view>
          <!-- 下面部分结束 -->
        </view>
      </view>
      <!-- 每一项结束 -->
    </view>
    <!-- 列表结束 -->
  </view>
</template>

<script>
  export default {
    data() {
      return {
        // 设备名称
        equi_name: '',
        // 设备index
        equi_index: 0,
        // 附近设备列表
        near_list: [],
        // 设备列表
        equi_list: [],
        // 设备id
        device_id: 0,
        // 设备名称
        device_name: '',
        // 服务id
        service_id: 0,
        // uuid
        uuid: 0,
        // 更新文件内容
        buf: '',
      }
    },
    methods: {
      // 蓝牙开始
      // 初始化蓝牙
      openBluetoothAdapter() {
        this.near_list = []
        uni.showLoading({
          title: '蓝牙初始化中',
        })
        uni.openBluetoothAdapter({
          success: (res) => {
            uni.hideLoading()
            this.showMsg('初始化成功')
            // 扫描设备
            this.startBluetoothDevicesDiscovery()
          },
          fail: (res) => {
            this.showMsg('请打开蓝牙')
            uni.setStorageSync('is_connect', false)
            if (res.errCode === 10001) {
              uni.onBluetoothAdapterStateChange(function (res) {
                // 监听蓝牙适配器是否打开，若打开则自动搜索蓝牙设备(onBluetoothAdapterStateChange)
                if (res.available) {
                  console.log(res.available)
                  this.startBluetoothDevicesDiscovery()
                }
              })
            }
          },
        })
      },
      // 扫描设备
      startBluetoothDevicesDiscovery() {
        uni.startBluetoothDevicesDiscovery({
          allowDuplicatesKey: true,
          success: (res) => {
            // 监听扫描到的设备
            this.onBluetoothDeviceFound()
          },
        })
      },
      // 监听扫描到的设备
      onBluetoothDeviceFound() {
        uni.onBluetoothDeviceFound((res) => {
          res.devices.forEach((device) => {
            // 过滤掉没有名字的设备
            if (!device.name && !device.localName) return
            // 这么操作是为了去除重复
            const foundDevices = this.near_list // 将数据中的数组复制一份,利用动态绑定方式，不断复制最新的数组
            const idx = this.inArray(foundDevices, 'deviceId', device.deviceId)
            if (idx === -1) {
              this.near_list.push(device) // 数组里没有的的就向里面添加数据，保证没有重复[uni写法]
            }
          })
        })
      },
      // 连接蓝牙设备
      connectEqui(e) {
        console.log('点击连接设备', e)
        uni.showLoading({
          title: '正在连接设备',
        })
        let obj = {}
        obj.title = e.name
        obj.eq_id = e.deviceId
        obj.is_show = false
        obj.info = e
        this.equi_list.push(obj)
        uni.setStorageSync('my_list', this.equi_list)
        if (uni.getStorageSync('my_list').length > 0) {
          let my_list = uni.getStorageSync('my_list')
          my_list.forEach((item) => {
            if (item.eq_id == e.deviceId) {
              uni.setStorageSync('device_name', item.title)
            }
          })
        } else {
          uni.setStorageSync('device_name', e.name)
        }
        console.log('我的设备列表', this.equi_list)
        console.log('点击蓝牙设备', e)
        this.device_id = e.deviceId
        this.device_name = e.name
        uni.setStorageSync('device_id', e.deviceId)
        // 将设备名称也传递给全局变量
        uni.createBLEConnection({
          deviceId: this.device_id,
          success: (res) => {
            // 设置蓝牙最大传输单元
            this.setBlueTooth(this.device_id)

            uni.setStorageSync('equi_list', this.equi_list)
            // this.connected = true,
            console.log('连接时获取设备id', this.device_id)
            setTimeout(() => {
              this.getBLEDeviceServices()
            }, 1000) // 这里必须要延迟才行这是一个bug
            console.log('连接设备成功', res)
            // this.stopBluetoothDevicesDiscovery() // 此时停止蓝牙搜索
            uni.setStorageSync('is_connect', true)
          },
          fail: (err) => {
            console.log('建立连接失败', err)
            if (uni.getStorageSync('is_connect')) {
              uni.showToast({
                title: '设备已连接',
                icon: 'none',
              })
            } else {
              uni.showToast({
                title: '建立连接失败',
                icon: 'none',
              })
            }
            return
          },
        })
      },
      // 获取设备信息
      getBLEDeviceServices() {
        uni.getBLEDeviceServices({
          deviceId: this.device_id,
          success: (res) => {
            for (let i = 0; i < res.services.length; i++) {
              if (res.services[i].isPrimary) {
                // 将服务id存储添加到全局服务id数组中
                this.service_id = res.services[i].uuid
                uni.setStorageSync('service_id', res.services[i].uuid)
                console.log(`服务id:${i}`, this.serviceId)
                this.getBLEDeviceCharacteristics() // 获取蓝牙设备某个服务中所有特征值
                return
              }
            }
          },
          fail: (err) => {
            uni.showToast({
              title: '获取服务失败',
              icon: 'none',
            })
            return
          },
        })
      },
      // 获取设备的所有特征值
      getBLEDeviceCharacteristics() {
        uni.getBLEDeviceCharacteristics({
          // 设备id与服务id必须要给
          deviceId: this.device_id,
          serviceId: this.service_id,
          success: (res) => {
            uni.hideLoading()
            console.log('------该特征值可写', res)
            if (!res.characteristics[0].properties.write) {
              this.showMsg('设备连接错误')
              return
            }
            uni.showToast({
              title: '设备连接成功',
            })
            // 保存uuid
            this.uuid = res.characteristics[0].uuid
            uni.setStorageSync('uuid', res.characteristics[0].uuid)
            console.log('获取设备特征值', res)
            if (res.characteristics[0].properties.read) {
              console.log('该特征值可读')
              uni.readBLECharacteristicValue({
                deviceId: this.device_id,
                serviceId: this.service_id,
                characteristicId: res.characteristics[0].uuid,
                complete(back) {
                  console.log('蓝牙返回值', back)
                },
              })
            }
            if (res.characteristics[0].properties.write) {
              // 如果可写入调用crc校验并写入16进制
              this.crcTest('00 AA 55 AA')
            }
            // 确保对应服务id下的特征值id具备监听数据变化的特性
            if (
              res.characteristics[0].properties.notify ||
              res.characteristics[2].properties.indicate
            ) {
              uni.notifyBLECharacteristicValueChange({
                deviceId: this.device_id,
                serviceId: this.service_id,
                characteristicId: res.characteristics[0].uuid,
                state: true, // 是否启用notify通知
                success: (res) => {
                  console.log('通知启用(notifyBLECharacteristicValueChange)', res)
                },
              })
            }
          },
          fail(res) {
            console.log('获取蓝牙设备特征值失败(getBLEDeviceCharacteristics)', res)
          },
          complete: (res) => {
            console.log('连接完成后的返回值-----', res)
          },
        })

        // 操作之前先监听，保证第一时间获取数据（value就是特征值当前最新的值）
        // 监听低功耗蓝牙设备的特征值变化事件。必须先启用 notifyBLECharacteristicValueChange 接口才能接收到设备推送的 notification
        uni.onBLECharacteristicValueChange((res) => {
          console.log('特征值变化', res)
          // let str = parseInt(this.ab2hex(res.value), 16).toString(2)
          let str = this.ab2hex(res.value)
          uni.setStorageSync('val_change', str)
          console.log(str)
        })
      },
      // 停止搜索
      stopBluetoothDevicesDiscovery() {
        uni.stopBluetoothDevicesDiscovery()
        console.log('已停止蓝牙扫描(closeBluetoothAdapter)')
        uni.showToast({
          title: '蓝牙搜索已停止',
          icon: 'success',
        })
      },
      // 获取下载文件
      getBin() {
        let _this = this
        uni.downloadFile({
          // 更新文件地址
          url: 'https://akhehuoren.oss-cn-hangzhou.aliyuncs.com/test.bin',
          success(res) {
            // 获取文件内容
            var filePath = res.tempFilePath
            var pathArrayBuffer = uni.getFileSystemManager().readFileSync(filePath)
            var buf = new Uint8Array(pathArrayBuffer)
            _this.buf = buf
            // 获取文件大小并传入蓝牙开启OTA状态
            uni.getFileInfo({
              filePath,
              success(result) {
                // 文件大小
                let file_size = result.size.toString(16)
                let new_size = _this.prefixZero(file_size, 8)
                let arr = new_size.split('')
                let arr2 = []
                for (let i = 0; i < arr.length; i += 2) {
                  arr2.push(arr.slice(i, i + 2))
                }
                let arr3 = []
                arr2.forEach((item) => {
                  arr3.push(item[0] + item[1])
                })
                // str就是组成的16进制命令符
                let str = arr3.join(' ')
                // 进行crc验证并向蓝牙写入完整命令
                _this.crcTest('FE', '01', 'E0', str)
                console.log('组成的命令字符串', arr3)
                // 写入
                _this.upDateInfo()
              },
            })
          },
        })
      },
      // 向蓝牙写入下载文件内容
      upDateInfo() {
        let buf = this.buf
        let buf_arr = []
        // 将bin文件内容进行切割为119个字节一个数组
        for (let i = 0; i < buf.length; i += 120) {
          buf_arr.push(buf.slice(i, i + 120))
        }
        let i = 0
        buf_arr.forEach((item, index) => {
          // 获取num
          let num = i.toString().length < 2 ? '0' + i : i
          num = num.toString(16)
          // 调用更新时crc校验方法并写入指令
          this.updateCrc(num, item)
          i++
          num == 'FF' && (i = 0)
        })
      },
      // 自动补0
      prefixZero(num, n) {
        var num_length = n - num.length
        if (num_length < n) {
          for (var i = 0; i < num_length; i++) {
            num = '0' + num
          }
        }
        return num
      },
      // crc校验
      async crcTest(header, version, cmd_id, params) {
        var rawData, arr
        if (params) {
          params = params.split(' ')
          arr = [cmd_id, ...params]
          rawData = arr.join(' ')
        } else {
          rawData = cmd_id
        }
        console.log('这是params', rawData)
        const res = await this.$api.common.crc({
          rawData,
        })
        console.log('crc校验结果', res)
        if (res.code === 200) {
          let crc_list = res.data.data.split('')
          // 将id,data和crc校验结果 放入数组中
          var data_list = rawData.split(' ')
          data_list = [...data_list, crc_list[0] + crc_list[1], crc_list[2] + crc_list[3]]
          let options = {
            header,
            version,
            data: data_list,
          }
          this.writeBLECharacteristicValue(options)
        }
      },
      // 更新时的crc方法
      async updateCrc(num, params) {
        // var rawData, arr
        // if (params) {
        //   params = params.split(' ')
        //   arr = [cmd_id, ...params]
        //   rawData = arr.join(' ')
        // } else {
        //   rawData = cmd_id
        // }
        params = params.join(' ')
        console.log('这是params', params)
        const res = await this.$api.common.crc({
          rawData: params,
        })
        console.log('crc校验结果', res)
        if (res.code === 200) {
          let crc_list = res.data.data.split('')
          // 将id,data和crc校验结果 放入数组中
          var data_list = params.split(' ')
          data_list = [...data_list, crc_list[0] + crc_list[1], crc_list[2] + crc_list[3]]
          let options = {
            num,
            data: data_list,
          }
          console.log('options', options)
          this.writeBLECharacteristicValue(options)
        }
      },
    },
    onShow() {
      // 进行crc校验---蓝牙握手 第一个参数是header 第二个是版本号, 第三个是id,第四个是data数据
      // this.crcTest('FE', '01', '01')
      // 获取下载文件
      this.getBin()
      // 蓝牙初始化
      // this.openBluetoothAdapter()
    },
    onLoad(options) {},
  }
</script>

<style lang="scss">
  ::-webkit-scrollbar {
    width: 0;
    height: 0;
    color: transparent;
  }

  u-swipe-action {
    box-sizing: border-box;
  }

  .my-equi {
    width: 100%;
    height: 100%;

    .scroll-view {
      width: 100%;
      box-sizing: border-box;

      .eq-item {
        margin-bottom: 24rpx;
        border-radius: 8rpx;

        .top-title,
        .bottom-title {
          width: 120rpx;
          margin-right: 24rpx;
          font-family: PingFangSC-Regular, PingFang SC;
          font-size: 28rpx;
          font-weight: 400;
          color: #666;
        }

        .bottom-text {
          width: 500rpx;
        }

        .top-text {
          max-width: 400rpx;
        }

        .top-img {
          width: 24rpx;
          height: 24rpx;
        }
      }

      .eq-item:last-child {
        margin-bottom: 0;
      }
    }

    .pop-box {
      .title {
        font-family: PingFangSC-Medium, PingFang SC;
        font-size: 32rpx;
        font-weight: 500;
        color: #333;
      }

      .textarea {
        height: 456rpx;
        font-family: PingFangSC-Regular, PingFang SC;
        font-size: 28rpx;
        font-weight: 400;
        color: #999;
        border: 2rpx solid #e1e1e1;
        border-radius: 16rpx;

        textarea {
          height: 100%;
        }
      }

      .btn {
        font-family: PingFangSC-Regular, PingFang SC;
        font-size: 32rpx;
        font-weight: 400;
        color: #fff;
        background: linear-gradient(90deg, #97cefc 0%, #5690c1 100%);
        border-radius: 44rpx;
      }
    }
  }
</style>
